﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ProcessRoll.Models;
using ProcessRoll.Utilities;
using System.Web.Helpers;
using System.Collections;
using System.Web.Script.Serialization;
using M = ProcessRoll.Models;
using ProcessRoll.BLL;
namespace ProcessRoll.Controllers
{
    public class ProcessRollController : Controller
    {

        //
        // GET: /ProcessRoll/

        public ViewResult Index()
        {
            return View(CH.GetAllData<Process>());
        }

        //
        // GET: /ProcessRoll/Details/5

        public ViewResult Details(int? id)
        {

            return View(CH.GetDataById<Process>(id));
        }


        public ActionResult Design(int? id)
        {
            return View(id);
        }

        public JsonResult GetProcess(int processid)
        {
            var p = CH.GetAllData<Process>(item => item.ID == processid, "Fields", "Conditions", "Queues").FirstOrDefault();

            List<object> jfields = new List<object>();
            var orderedfields = p.Fields.OrderBy(f => f.Sequence);
            foreach (var child in orderedfields)
            {
                jfields.Add(GetFieldJson(child));
            }
            List<object> jconditions = new List<object>();
            foreach (var child in p.Conditions)
            {
                jconditions.Add(GetConditionJson(child));
            }
            List<object> jqueues = new List<object>();

            if (p.Queues != null)
            {
                var orderedqueue = p.Queues.OrderBy(q => q.Sequence);
                foreach (var child in orderedqueue)
                {
                    List<object> containers = new List<object>();
                    var containersData = CH.GetAllData<Container>(i => i.QueueID == child.ID);
                    foreach (var container in containersData)
                    {
                        List<object> nodedatas = new List<object>();
                        var root = CH.GetAllData<NodeData>(n => n.ContainerID == container.ID && n.ParentNodeDataID == null);
                        var rootjson = GetNodeDataJson(root.FirstOrDefault());
                        var t = new List<object>(); t.Add(rootjson);

                        List<object> activities = new List<object>();
                        var ainc = CH.GetAllData<Activity>(a => a.ContainerID == container.ID && a.ProcessID == p.ID);
                        foreach (var a in ainc)
                        {
                            activities.Add(GetActivityJson(a));
                        }
                        containers.Add(new { id = container.ID, QueueID = container.QueueID, ProcessID = p.ID, NodeDatas = t, Activities = activities });
                    }

                    jqueues.Add(new
                    {
                        id = child.ID,
                        Containers = containers,
                        ProcessID = child.ProcessID
                    });
                }
            }
            var jp = new { fields = jfields, conditions = jconditions, queues = jqueues };
            return Json(p, JsonRequestBehavior.AllowGet);
            //return Json(jp, JsonRequestBehavior.AllowGet);
        }

        #region Read
        object GetActivityInstanceJson(ActivityInstance ai)
        {
            return ai == null ? null :
             new
            {
                Activity = GetActivityJson(ai.Activity),
                ActivityID = ai.ActivityID,
                ExameApprove = GetExameApprove(ai.ExameApprove),
                ExameApproveID = ai.ExameApproveID
            };
        }

        private object GetExameApprove(ExameApprove exameApprove)
        {
              List<object> fis = new List<object>();
              if (exameApprove == null)
                  return null;
              else
              {
                  exameApprove.FieldInstances.ForEach(fi => fis.Add(GetFieldInstanceJson(fi)));
                  return new
                  {
                      FieldInstances = fis,
                      ID = exameApprove.ID,
                      ResultEA = exameApprove.ResultEA,
                      Approver = exameApprove.Approver,
                      Comments = exameApprove.Comments
                  };
              }
        }

        private object GetFieldInstanceJson(FieldInstance fi)
        {
            return fi == null ? null :
             new
            {
                id = fi.ID,
                FieldName = fi.FieldName,
                FieldValue = fi.FieldValue
            };
        }

        object GetProcessInstanceJson(ProcessInstance pi)
        {
            if (pi == null)
                return null;
            else
            {
                List<object> ais = new List<object>();
                pi.ActivityInstances.ForEach(a => ais.Add(GetActivityInstanceJson(a)));
                return new
                {
                    ActivityInstances = ais,
                    id = pi.ID
                };
            }
        }

        object GetFieldJson(Field child)
        {
            return new
            {
                id = child.ID,
                FieldName = child.FieldName,
                DefaultValue = child.DefaultValue,
                ControlType = child.ControlType,
                OptionValue = child.OptionValue,
                Must = child.Must,
                Level = child.Level,
                Initial = child.Initial,
                Description = child.Description,
                FieldWidth = child.FieldWidth,
                ProcessID = child.ProcessID,
                Min = child.Min,
                Max = child.Max
            };
        }

        object GetConditionJson(Condition child)
        {
            if (child == null)
                return null;
            else
                return new
                {
                    id = child.ID,
                    ConditionName = child.ConditionName,
                    ConditionOperator = child.ConditionOperator,
                    ConditionType = child.ConditionType,
                    ConditionValue = child.ConditionValue,
                    Field = child.Field.FieldName,
                    ProcessID = child.ProcessID
                };
        }

        private object GetNodeDataJson(NodeData node)
        {
            if (node == null) return null;
            var condition = CH.GetDataById<Condition>(node.ConditionID);
            var cj = GetConditionJson(condition);
            var item = new { id = node.ID, Condition = cj, Operator = node.Operator, ContainerID = node.ID, ProcessID = node.ProcessID, ChildrenData = new List<object>() };

            if (node.ChildrenData != null)
            {
                foreach (var child in node.ChildrenData)
                {
                    var childjson = GetNodeDataJson(child);
                    item.ChildrenData.Add(childjson);
                }
            }

            return item;
        }
        object GetActivityJson(Activity a)
        {
            if (a == null)
                return null;
            else
                return new
            {
                id = a.ID,
                ActivityName = a.ActivityName,
                ActivityType = a.ActivityType,
                ActivityDuration = a.ActivityDuration,
                Level = a.Level,
                ActivityRole = a.ActivityRole
            };
        }
        #endregion

        #region Save
        [HttpPost]
        public JsonResult SaveProcess(Process p)
        {
            if (p.ID > 0)
            {
                UpdateProcessData(p);
            }
            else
            {
                var tfields = p.Fields;
                var tconditions = p.Conditions;
                var tqueues = p.Queues;
                p.Fields = null;
                p.Conditions = null;
                p.Queues = null;

                CH.Create<Process>(p);

                p.Fields = tfields;
                p.Conditions = tconditions;
                p.Queues = tqueues;

                UpdateProcessData(p);
            }
            return new JsonResult();
        }

        void UpdateProcessData(Process p)
        {
            //更新表单
            if (p.Fields != null)
            {
                int fl = 0;
                p.Fields.ForEach(f => f.Sequence = fl = fl + 1);
                foreach (var f in p.Fields)
                {
                    if (f.ProcessID == null && p.ID > 0)
                        f.ProcessID = p.ID;
                }
                CH.EditRange<Field>(CH.GetAllData<Field>(i => i.ProcessID == p.ID), p.Fields);
            }

            if (p.Conditions != null)
            {
                //更新conditionid
                foreach (var c in p.Conditions)
                {
                    var tf = CH.GetAllData<Field>(f => f.ProcessID == p.ID && f.FieldName == c.Field.FieldName).FirstOrDefault();

                    c.FieldID = tf == null ? null : (int?)tf.ID;
                    c.Field = null;
                    if (c.ProcessID == null && p.ID > 0)
                        c.ProcessID = p.ID;
                }

                //更新条件
                CH.EditRange<Condition>(CH.GetAllData<Condition>(i => i.ProcessID == p.ID), p.Conditions);
            }

            var originContainers = CH.GetAllData<Container>(i => i.ProcessID == p.ID);
            List<Container> currentContainers = new List<Container>();

            var originQueue = CH.GetAllData<M.Queue>(i => i.ProcessID == p.ID);
            List<M.Queue> currentQueues = new List<M.Queue>();

            //初始化当前队列，容器和环节的值
            if (p.Queues != null)
            {
                int ql = 0;
                p.Queues.ForEach(que => que.Sequence = ql = ql + 1);
                currentQueues.AddRange(p.Queues);
                foreach (var q in p.Queues)
                {
                    if (q.ProcessID == null && p.ID > 0)
                        q.ProcessID = p.ID;

                    var tempq = q.Containers;
                    q.Containers = null;
                    if (q.ID > 0)
                        CH.Edit<M.Queue>(q);
                    else
                        CH.Create<M.Queue>(q);
                    q.Containers = tempq;
                    if (q.Containers != null)
                    {
                        int cl = 0;
                        q.Containers.ForEach(c => c.Sequence = cl = cl + 1);

                        currentContainers.AddRange(q.Containers);
                        foreach (var c in q.Containers)
                        {
                            c.QueueID = q.ID;
                            if (c.ProcessID == null && p.ID > 0)
                                c.ProcessID = p.ID;
                            var tempc = c.NodeDatas;
                            c.NodeDatas = null;
                            var tempa = c.Activities;
                            c.Activities = null;
                            if (c.ID > 0)
                                CH.Edit<Container>(c);
                            else
                                CH.Create<Container>(c);
                            c.NodeDatas = tempc;
                            c.Activities = tempa;
                            //重写所有node节点
                            DeleteNodeDatas(c.NodeDatas);
                            if (c.NodeDatas != null)
                            {
                                //保存
                                SetNodeDatas(c.NodeDatas, c.ID);
                                c.NodeDatas = null;
                            }

                            //更新环节
                            int al = 0;
                            c.Activities.ForEach(a => a.Sequence = al = al + 1);
                            foreach (var a in c.Activities)
                            {
                                a.ProcessID = c.ProcessID;
                                a.ContainerID = c.ID;
                            }
                            var originActivity = CH.GetAllData<Activity>(a => a.ProcessID == p.ID && a.ContainerID == c.ID);
                            CH.EditRange<Activity>(originActivity, c.Activities);
                        }
                        q.Containers = null;
                    }
                }

                //更新容器
                var toDeleteContianers = originContainers.FindAll(o => currentContainers.FirstOrDefault(c => c.ID == o.ID) == null);

                //删除同一个Q下容器的集合
                DeleteContainersWithItsNodes(toDeleteContianers);


                CH.Edit<Process>(p);
            }

            //删除多余的queue
            var toDeleteQueues = originQueue.FindAll(o => currentQueues.FirstOrDefault(c => c.ID == o.ID) == null);
            if (toDeleteQueues.Count > 0)
            {
                foreach (var q in toDeleteQueues)
                {
                    DeleteContainersWithItsNodes(CH.GetAllData<Container>(c => c.QueueID == q.ID));
                    CH.Delete<M.Queue>(q.ID);
                }
            }
        }

        void DeleteContainersWithItsNodes(List<Container> cs)
        {
            if (cs != null)
            {
                foreach (var c in cs)
                {
                    var firstnode = CH.GetAllData<NodeData>(n => n.ParentNodeDataID == null && n.ContainerID == c.ID);
                    DeleteNodeDatas(firstnode);
                    CH.Delete<Container>(c.ID);
                }
            }
        }

        void DeleteNodeDatas(List<NodeData> ns)
        {
            if (ns != null)
            {
                foreach (var n in ns)
                {
                    if (n.ChildrenData != null)
                    {
                        DeleteNodeDatas(n.ChildrenData);
                    }
                    if (n.ID > 0)
                        CH.Delete<NodeData>(n.ID);
                }
            }
        }

        private void SetNodeDatas(List<NodeData> list, int containerid)
        {
            foreach (var n in list)
            {
                if (n.Condition != null)
                {
                    var tc = CH.GetAllData<Condition>().FirstOrDefault(i => i.ConditionName == n.Condition.ConditionName);
                    n.ConditionID = tc.ID;
                    n.Condition = null;

                }
                n.ContainerID = containerid;
                n.ID = 0;
                var temp = n.ChildrenData;
                n.ChildrenData = null;
                CH.Create<NodeData>(n);
                n.ChildrenData = temp;

                if (n.ChildrenData != null)
                {
                    foreach (var child in n.ChildrenData)
                    {
                        child.ParentNodeDataID = n.ID;
                    }
                    SetNodeDatas(n.ChildrenData, containerid);
                }
            }
        }
        #endregion

        #region Preview
        [HttpPost]
        public ActionResult Preview(Process p)
        {
            return View(p);
        }

        public ActionResult Preview(int? id)
        {
            return View(id);
        }

        public JsonResult GetNextParticipant(ProcessInstance pi)
        {
            var fea = new FlowEA(pi);
            var nextpi = fea.GetNextParticipant();
            var result = GetProcessInstanceJson(nextpi);

            return Json(result);
        }
        #endregion

        public ActionResult PeopleFinder(string condition)
        {
            List<Employee> data;
            if (condition == "all")
                data = CH.GetAllData<Employee>();
            else
            {
                data = CH.GetAllData<Employee>(item => item.FullName.Contains(condition.Trim()));

            }
            List<object> jdata = new List<object>();
            foreach (var child in data)
            {
                jdata.Add(new { id = child.ID, fullname = child.FullName });
            }

            return Json(jdata);
        }

        public ActionResult Delete(int? id)
        {
            Process process = CH.GetDataById<Process>(id);
            return View(process);
        }

        //
        // POST: /ProcessRoll/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int? id)
        {
            Process process = CH.GetDataById<Process>(id);
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
    }
}